import numpy as np
import re


def load_data_set():
    posting_list = [['my','dog','has','flea','problems','help','please'],
                 ['maybe','not','take','him','to','dog','park','stupid'],
                 ['my','dalmation','is','so','cute','I','love','him'],
                 ['stop','posting','stupid','worthless','garbage'],
                 ['my','licks','ate','my','steak','how','to','stop','him'],
                 ['quit','buying','worthless','dog','food','stupid']]
    class_vec = [0,1,0,1,0,1]             # 1代表侮辱性语言， 0代表正常的言论
    return posting_list, class_vec

def create_vocab_list(data_set):
    vocab_set = set([])             # 设置为空set
    for document in data_set:
        vocab_set = vocab_set | set(document)           # | 取的是两个的并集，都是set，不会出现重复值
    return list(vocab_set)                              # 返回的是传入数据的非重复集合

# 这个函数好像是想把某句话转化为向量，还不涉及到判断是否为侮辱性文字
# 所有词汇为0   这一句出现了哪些单词，哪个单词就为1
def set_of_words2vec(vocab_list,input_set):
    return_vec = [0] * len(vocab_list)          # 用 0 格式化为长度为非重复集合的长度值
    for word in input_set:
        if word in vocab_list: 
            # vocab_list是load_data_set函数的创建的，是随机列表，导致此处我想判断的文本，所对应的index也是随机的，
            # 不过index和文本是对应的，所以下面的方法是可行的
            return_vec[vocab_list.index(word)] += 1
        else:
            print('the word %s is not in my Vocabulary!' % word)
    return return_vec                           # 返回的是 我输入的文本转成的向量

# 这个函数好像是想把某句话转化为向量，遇到一个词出现2次及以上  
def bag_of_words2vec(vocab_list,input_set):
    return_vec = [0] * len(vocab_list)          # 用 0 格式化为长度为非重复集合的长度值
    for word in input_set:
        if word in vocab_list: 
            # vocab_list是load_data_set函数的创建的，是随机列表，导致此处我想判断的文本，所对应的index也是随机的，
            # 不过index和文本是对应的，所以下面的方法是可行的
            return_vec[vocab_list.index(word)] += 1         # 和set_of_words2vec只差这一个自+1
        else:
            print('the word %s is not in my Vocabulary!' % word)
    return return_vec  



def train_nb0(train_matrix, train_category):
    num_train_docs = len(train_matrix)      # =6
    num_words = len(train_matrix[0])        # =31
    p_abusive = sum(train_category)/float(num_train_docs)               # 计算出为侮辱性语言的概率
    #计算概率时，需要计算多个概率的乘积以获得文档属于某个类别的概率，即计算p(w0|ci)*p(w1|ci)*...p(wN|ci)，然后当其中任意一项的值为0，
    #那么最后的乘积也为0.为降低这种影响，采用拉普拉斯平滑，在分子上添加a(一般为1)，分母上添加ka(k表示类别总数)，
    #即在这里将所有词的出现数初始化为1，并将分母初始化为2*1=2
    p0_num = np.ones(num_words)
    p1_num = np.ones(num_words)
    p0_denom = 2
    p1_denom = 2
    for i  in range(num_train_docs):
        if train_category[i] == 1:
            p1_num += train_matrix[i]
            p1_denom += sum(train_matrix[i])
        else:
            p0_num += train_matrix[i]
            p0_denom += sum(train_matrix[i])
     # 出自机器实战55页，这个就像侮辱性言论p1_denom个，每个词出现的次数组成np.array为p1_num，概率就是p1_num/p1_denom
    p1_vect = np.log(p1_num/p1_denom)     
    p0_vect = np.log(p0_num/p0_denom)
    return p0_vect, p1_vect,p_abusive       # 取对数是因为避免很小的数连乘导致太小，被解释器四舍五入为0


def classify_nb(vec2classify, p0_vec, p1_vec, p_class1):            # p_class1传入的是侮辱性言论的概率
    p1 = sum(vec2classify * p1_vec) + np.log(p_class1)              # 相加因为取了对数，ln(a+b)=ln(a)+ln(b)
    p0 = sum(vec2classify * p0_vec) + np.log(1.0-p_class1)          # 每个单词为正常言论的概率 * 一篇文章是正常言论的概率
    sss = np.dot(vec2classify, p0_vec)
    qqq =np.dot(vec2classify, p1_vec)
    www = vec2classify
    eee = p1_vec
    if p1 > p0:
        return 1
    else:
        return 0


#----------------------------------------------------------------------
def testing_nb():
    data_set,  class_vec = load_data_set()                      
    my_valcab_list = create_vocab_list(data_set)
    train_mat = []
    for postin_doc in data_set:
        train_mat.append(bag_of_words2vec(my_valcab_list, postin_doc))
    # 返回的是正常言论每个单词出现的概率，侮辱性的概率每个单词出现的概率，和一篇文章是侮辱性的概率
    p0_vect, p1_vect,p_abusive = train_nb0(train_mat, class_vec)            
    test_entry = ['love', 'my', 'dalmation']
    this_doc = np.array(bag_of_words2vec(my_valcab_list, test_entry))
    print(test_entry, 'classified as: ', classify_nb(this_doc, p0_vect, p1_vect, p_abusive))
    test_entry = ['stupid', 'garbage','love','love','love','love','love','love','love','love','love','love','love','love','love','love']
    this_doc = np.array(bag_of_words2vec(my_valcab_list, test_entry))
    print(test_entry, 'classified as: ', classify_nb(this_doc, p0_vect, p1_vect, p_abusive))    
    


# 之前的是给定的数据，现在自己切分文本，有用到正则
my_sent = 'this book is the best book on python or M.L. I have ever laid.'
reg_ex = re.compile('\\W*')
# list_tokens = reg_ex.split(my_sent)
# list_tokens = my_sent.split(reg_ex)
# tokens = [tokens.lower() for tokens in list_tokens if len(tokens)>0]


list_o_posts, list_classes = load_data_set()
vocab_list = create_vocab_list(list_o_posts)
word2vec = set_of_words2vec(vocab_list, list_o_posts[0])
train_mat = []
for i in list_o_posts:
    train_mat.append(set_of_words2vec(vocab_list, i))
p0, p1, pa = train_nb0(train_mat, list_classes)
test_entry = ['love', 'my', 'love']

test_vec = set_of_words2vec(vocab_list, test_entry)
p_test = classify_nb(test_vec, p0, p1, pa)


#testing_nb()
#print(p_abusive)
#print('p1_vect : %s' %p1_vect)
#print('p0_vect : %s' %p0_vect)
# print(data_set[0])
# print(create_vocab_list(data_set))
# print(set_of_words2vec(create_vocab_list(data_set), data_set[0]))
    
    